﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml.Linq;
using System.IO;

namespace BulldogCMS.Core.Storage.Providers
{
    public class XMLContentTreeProvider : IContentTreeProvider
    {
        private XDocument _treeDoc = null;

        public XMLContentTreeProvider(XDocument treeDoc)
        {
            this._treeDoc = treeDoc;
        }

        public IEnumerable<Node> GetRootNodes(long? nodeID = null)
        {
            List<Node> nodes = new List<Node>();
            foreach (XElement nodeEl in this._treeDoc.Root.Elements("node"))
            {
                Node node = this.GetNode(nodeEl,"/","/");
                if (node.ContentTreeProvider == null)
                {
                    node.ContentTreeProvider = this;
                }
                nodes.Add(node);
            }
            return nodes;
        }

        public IEnumerable<Node> GetNodes(Node parentNode)
        {
            List<Node> childNodes = new List<Node>();
            string pathPointer = parentNode.CurrentProviderPath;
            XElement parentNodeEl = this.GetNodeEl(_treeDoc.Root, pathPointer);
            if (parentNodeEl != null && parentNodeEl.Element("nodes") != null)
            {
                foreach (XElement childNode in parentNodeEl.Element("nodes").Elements())
                {
                    Node node = this.GetNode(childNode);
                    if (node.ContentTreeProvider == null)
                    {
                        node.ContentTreeProvider = this;
                    }
                    node.Path = parentNode.Path.CombineUrl(node.Name);
                    node.CurrentProviderPath = parentNode.CurrentProviderPath.CombineUrl(node.Name);
                    childNodes.Add(node);
                }
            }
            return childNodes;
        }

        // /Content/ComputerShop/About
        private XElement GetNodeEl(XElement element, string pathPointer)
        {
            string currentNodeName = this.ExtractCurrentElementName(pathPointer);
            pathPointer = this.GetNextPathPointer(pathPointer);
            if (currentNodeName == null) return element;

            while (currentNodeName != null)
            {
                bool elementFound = false;
                foreach (XElement nodeEl in element.Elements())
                {
                    if (nodeEl.GetAttributeValue<string>("name") == currentNodeName)
                    {
                        element = nodeEl;
                        currentNodeName = this.ExtractCurrentElementName(pathPointer);
                        pathPointer = this.GetNextPathPointer(pathPointer);
                        elementFound = true;
                        break;
                    }
                }
                if (!elementFound)
                {
                    return null;
                }
            }
            return element;
        }

        // /Content/ComputerShop/About
        private string ExtractCurrentElementName(string pathPointer)
        {
            try
            {
                pathPointer = pathPointer.TrimStart('/');
                int nextSlashPosition = pathPointer.IndexOf('/');
                if (nextSlashPosition > 0)
                {
                    return pathPointer.Substring(0, nextSlashPosition);
                }
                else
                {
                    return pathPointer;
                }
            }
            catch { }
            return null;
        }

        private string GetNextPathPointer(string pathPointer)
        {
            try
            {
                pathPointer = pathPointer.TrimStart('/');
                if (!pathPointer.Contains('/')) return null;
                int nextSlashPosition = pathPointer.IndexOf('/');
                return pathPointer.Substring(nextSlashPosition + 1);
            }
            catch
            {
                return null;
            }
        }

        private Node GetNode(XElement nodeEl, string currentPath = null, string currentProviderPath = null)
        {
            Node node = new Node()
            {
                ID =                        nodeEl.GetAttributeValue<long>("ID"),
                Name =                      nodeEl.GetAttributeValue<string>("name"),
                TemplateName =              nodeEl.GetAttributeValue<string>("template"),
                ContentProviderTypeName =   nodeEl.GetAttributeValue<string>("providerType"),
                Mode =                      nodeEl.GetAttributeValue<NodeMode>("mode")
            };
            if (currentPath != null)
            {
                node.Path = currentPath.CombineUrl(nodeEl.GetAttributeValue<string>("name"));
            }
            if (currentProviderPath != null)
            {
                node.CurrentProviderPath = currentProviderPath.CombineUrl(nodeEl.GetAttributeValue<string>("name"));
            }

            if (node.ContentProviderTypeName != null)
            {
                node.ContentTreeProvider = node.ContentProviderTypeName.Instantiate<IContentTreeProvider>();
                node.ProviderRoot = true;

                // parameters
                if (nodeEl.Element("parameters") != null)
                {
                    foreach (XElement parEl in nodeEl.Element("parameters").Elements())
                    {
                        node.ContentTreeProvider.SetParameter(parEl.GetAttributeValue<string>("name"), parEl.GetAttributeValue<string>("value"));
                    }
                }
                // /parameters
            }


            return node;
        }

        public void SetParameter(string name, string value)
        {
            throw new NotImplementedException();
        }

        public NodeVersion GetNodeVersion(Node node, string languageIdent, int versionNumber)
        {
            throw new NotImplementedException();
        }

        // /Content
        public Node GetNode(string currentProviderPath, string name, long parentNodeID)
        {
            string normalizedPath = currentProviderPath.Trim('/');
            string[] paths = normalizedPath.Split('/');
            XElement currentElement = this._treeDoc.Root;
            foreach (string pathPart in paths)
            {
                currentElement = currentElement.Elements("node").Where(p => p.Attribute("name").Value == pathPart).FirstOrDefault();
                if (currentElement == null)
                {
                    return null;
                }
                else
                {
                    currentElement = currentElement.Element("nodes");
                    if (currentElement == null)
                    {
                        return null;
                    }
                }

            }
            currentElement = currentElement.Elements().Where(p => p.Attribute("name").Value == name).FirstOrDefault();
            if (currentElement == null)
            {
                return null;
            }
            return this.GetNode(currentElement, currentProviderPath: currentProviderPath);
        }

        public Node CreateNewNode(Node node)
        {
            throw new NotImplementedException("This provider does not support creating new nodes");
        }


        public Node UpdateNode(Node node)
        {
            throw new NotImplementedException();
        }

        public void DeleteNode(Node node)
        {
            throw new NotImplementedException();
        }

        public NodeVersion CreateNewVersion(Node node, NodeVersion newVersion)
        {
            throw new NotImplementedException();
        }

        public NodeVersion UpdateVersion(Node node, NodeVersion updatedVersion)
        {
            throw new NotImplementedException();
        }

        public NodeVersion DeleteVersion(Node node, NodeVersion versionToBeDeleted)
        {
            throw new NotImplementedException();
        }

        public bool ReadOnly
        {
            get { return true; }
        }
    }
}